package finbudgettable.client.ui.grid.cell.status;

import java.util.Date;

import com.google.gwt.cell.client.AbstractCell;
import com.google.gwt.cell.client.ValueUpdater;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.BrowserEvents;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.resources.client.ClientBundle;
import com.google.gwt.resources.client.CssResource;
import com.google.gwt.resources.client.ImageResource;
import com.google.gwt.safehtml.client.SafeHtmlTemplates;
import com.google.gwt.safehtml.shared.SafeHtml;
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
import com.google.gwt.safehtml.shared.SafeUri;

import finbudget.client.ui.table.Record;
import finbudgettable.client.ui.grid.CellGrid;
import finbudgettable.client.ui.grid.cell.info.InfoColumn;
import finbudgettable.client.ui.grid.event.RecordChangedEvent;
import finbudgettable.client.ui.grid.event.RecordChangingEvent;

public class StatusCell extends AbstractCell<Record> {

    public interface Resources extends ClientBundle {

        interface Style extends CssResource {
            @ClassName("b-status-cell")
            String bStatusCell();

            @ClassName("b-status-header")
            String bStatusHeader();

            @ClassName("b-readytobedeleted-cellhidden")
            String bReadyToBeDeletedCellHidden();

            @ClassName("b-readytobedeleted-cellvisible")
            String bReadyToBeDeletedCellVisible();
        }

        @Source("edit.png")
    	public ImageResource edit();

        @Source("delete_dark_16x16.png")
    	public ImageResource deleteDark();

        @Source("StatusCell.css")
        Style style();
    }

    interface Template extends SafeHtmlTemplates {
        @Template("<div class='{0}'><img title='{1}' src='{2}'/></div>")
        SafeHtml divImgBundle(String className, String altText, SafeUri url);
    }

    private final CellGrid grid;
    public static final Resources RESOURCES;
    private static final Template TEMPLATE = GWT.create(Template.class);
    private static final Messages MESSAGES = GWT.create(Messages.class);
    private long timeToIgnoreMouseOverEvents;

    static {
    	RESOURCES = GWT.create(Resources.class);
        RESOURCES.style().ensureInjected();
//        CellGrid.StandardResources.Style style = CellGrid.STANDARD_RESOURCES.cellTableStyle();
//        StyleInjector.inject("." + style.cellTableHoveredRow() + " ." + RESOURCES.style().bReadyToBeDeletedCell() + ":hover{visibility: visible}");
//        StyleInjector.inject("." + style.cellTableHoveredRowCell() + " ." + RESOURCES.style().bReadyToBeDeletedCell() + "{visibility: visible}");
    }

    private boolean isVisible;

    public StatusCell(CellGrid grid) {
        super(BrowserEvents.CLICK, BrowserEvents.KEYDOWN, BrowserEvents.MOUSEOVER, BrowserEvents.MOUSEOUT);
    	this.grid = grid;
    }

	@Override
	public void render(Context context, Record record, SafeHtmlBuilder sb) {
		if (record != null) {
			switch (getRecordStatus(record)) {
			case UNCHANGED:
				if (grid.canDeleteRecords()) {
					sb.append(TEMPLATE.divImgBundle(isVisible ? RESOURCES.style().bReadyToBeDeletedCellVisible() : RESOURCES.style().bReadyToBeDeletedCellHidden(),
							MESSAGES.delete(), finbudget.client.resources.Resources.INSTANCE.delete16x16().getSafeUri()));
				}
				break;
			case CHANGED:
				sb.append(TEMPLATE.divImgBundle(RESOURCES.style().bStatusCell(), MESSAGES.changed(), RESOURCES.edit().getSafeUri()));
				break;
			case TOBEDELETED:
				sb.append(TEMPLATE.divImgBundle(RESOURCES.style().bStatusCell(), MESSAGES.toBeDeleted(), RESOURCES.deleteDark().getSafeUri()));
				break;
			case ERROR:
				sb.append(TEMPLATE.divImgBundle(RESOURCES.style().bStatusCell(), record.status, finbudget.client.resources.Resources.INSTANCE.warn16x16().getSafeUri()));
				break;
			default:
				break;
			}
		}
	}

    @Override
    public void onBrowserEvent(Context context, Element parent, Record value, NativeEvent event, ValueUpdater<Record> updater) {
        super.onBrowserEvent(context, parent, value, event, updater);
        if (BrowserEvents.CLICK.equals(event.getType())) {
            onEnterKeyDown(context, parent, value, event, updater);
        } else if (BrowserEvents.MOUSEOVER.equals(event.getType())) {
        	if (new Date().getTime() > timeToIgnoreMouseOverEvents) {
	        	isVisible = true;
	        	if (getRecordStatus(value) == RecordStatus.UNCHANGED) {
	        		if (parent != null && parent.getFirstChildElement() != null) {
		        		parent.getFirstChildElement().removeClassName(RESOURCES.style().bReadyToBeDeletedCellHidden());
		        		parent.getFirstChildElement().setClassName(RESOURCES.style().bReadyToBeDeletedCellVisible());
	        		}
	        	}
        	}
        } else if (BrowserEvents.MOUSEOUT.equals(event.getType())) {
        	isVisible = false;
        	if (getRecordStatus(value) == RecordStatus.UNCHANGED) {
        		if (parent != null && parent.getFirstChildElement() != null) {
	        		parent.getFirstChildElement().setClassName(RESOURCES.style().bReadyToBeDeletedCellHidden());
	        		parent.getFirstChildElement().removeClassName(RESOURCES.style().bReadyToBeDeletedCellVisible());
        		}
        	}
        }
    }

    @Override
    protected void onEnterKeyDown(Context context, Element parent, Record record, NativeEvent event, ValueUpdater<Record> updater) {
        if (record != null && !record.isReadOnly() && grid.canDeleteRecords()) {
            grid.fireEvent(new RecordChangingEvent(record, InfoColumn.FIELD_NAME, record));
			switch (getRecordStatus(record)) {
			case UNCHANGED:
			case CHANGED:
				record.toDelete = true;
				break;
			case TOBEDELETED:
				record.toDelete = false;
				isVisible = false;
				timeToIgnoreMouseOverEvents = new Date().getTime() + 300L;
				break;
			case ERROR:
				record.status = null;
				record.toDelete = true;
				break;
			default:
				break;
			}
    		setValue(context, parent, record);
    		grid.fireEvent(new RecordChangedEvent(record));
        }
    }

	public static RecordStatus getRecordStatus(Record record) {
		if (record != null) {
			if (record.toDelete) {
				return RecordStatus.TOBEDELETED;
			}
			if (record.status != null) {
				return RecordStatus.ERROR;
			}
			if (record.isChanged) {
				return RecordStatus.CHANGED;
			}
		}
		return RecordStatus.UNCHANGED;
	}

}
